Java Differences topic
Syntactic and semantic differences between Java and the generated Dart bindings
This document highlights the key syntactic and semantic variations between Java and Dart and how JNIgen addresses them to ensure smooth interoperability.
Method overloading
Java supports overloading methods. This means that it can distinguish between two methods with the same name that have a different signature.
// Java
public class Calculator {
public int add(int a, int b) {
return a + b;
}
public double add(double a, double b) {
return a + b;
}
public float add(float a, float b) {
return a + b;
}
}
This is not the case for Dart. Each method of a class must have a unique name.
To overcome this limitation, JNIgen adds a dollar sign ($
) and a numeric
suffix to the end of the overloaded method name.
// Dart Bindings - Boilerplate omitted for clarity.
class Calculator extends JObject {
int add(int a, int b) { /* ... */ }
double add$1(double a, double b) { /* ... */ }
double add$2(double a, double b) { /* ... */ }
}
Warning
Running the code generator again on a different version of the library can map the methods differently if the order of the methods change or another overloading of the same method gets added.
Double check the doc comments on the generated methods to make sure you are calling your intended method.
You might wonder why the method isn't renamed to add1
instead of add$1
. The
reason is that a method named add1
could already exist in the Java class. On
the other hand, Java identifiers normally do not contain dollar signs.
Note
See Identifiers containing dollar signs to see what JNIgen does when identifiers contain dollar signs.
// Java
public class Calculator {
public int add(int a, int b) {
return a + b;
}
public double add(double a, double b) {
return a + b;
}
public float add(float a, float b) {
return a + b;
}
public int add1(int a) {
return a + 1;
}
public double add1(double a) {
return a + 1;
}
}
In this case, the generated code will be:
// Dart Bindings - Boilerplate omitted for clarity.
class Calculator extends JObject {
int add(int a, int b) { /* ... */ }
double add$1(double a, double b) { /* ... */ }
double add$2(double a, double b) { /* ... */ }
int add1(int a) { /* ... */ }
double add1$1(double a) { /* ... */ }
}
Fields and methods with the same name
In Java, we can have a field and a method with the same name. This is not possible in Dart.
// Java
public class Player {
// Player's personal duck!
public Duck duck;
// Lower your head!
public void duck() { /* ... */ }
}
JNIgen handles this similarly to method overloading. The
method with the same name as the field will be appended by a dollar sign ($
)
followed by a numeric suffix.
// Dart Bindings - Boilerplate omitted for clarity.
class Player extends JObject {
Duck get duck { /* ... */ };
set duck(Duck value) { /* ... */ }
void duck$1() { /* ... */ }
// If there were more `duck` methods they would be named
// `duck$2`, `duck$3`, ...
}
It is important to note that the order of renaming is fields-first
methods-second. So when both a field named duck
and a method named duck
exist, the field keeps its original name as seen above.
However the renaming happens for superclasses first. Consider this case.
// Java
public class Player {
// Lower your head!
public void duck() { /* ... */ }
}
public class DuckOwningPlayer extends Player {
// Player's personal duck!
public Duck duck;
}
The Player
class already has a method named duck
and no field with the same
name. So this will be the generated bindings for it:
// Dart Bindings - Boilerplate omitted for clarity.
class Player extends JObject {
void duck() { /* ... */ }
}
DuckOwningPlayer
inherits the duck()
method from Player
and adds a field
named duck
. This time, the field will be renamed as the method is simply
inherited.
// Dart Bindings - Boilerplate omitted for clarity.
class DuckOwningPlayer extends Player {
Duck get duck$1 { /* ... */ };
set duck$1(Duck value) { /* ... */ }
}
Identifiers containing dollar signs
JNIgen uses dollar signs in the generated code to fill the syntactic and semantic gaps between Java and Dart. This normally does not cause a problem as the Java language specificifaction suggests dollar signs should be used only in the generated code or, rarely, to access pre-existing names on legacy systems.
JNIgen replaces each single dollar sign with two dollar signs. For example
generated$method$2
will turn into generated$$method$$2
. This prevents name
collision as JNIgen-renamed identifiers will end with an odd number of dollar
signs (optionally followed by a numeric suffix).
Identifier starting with underscore (_
)
Unlike Java, Dart identifiers that start with an underscore are private. This means they are inaccessible outside their defining scope. Users should still be able to access public Java identifiers that start with an underscore from the generated Dart bindings. To allow this, JNIgen prepends such identifiers with a dollar sign to keep them public in Dart.
For example, _Example
in Java will be converted to $_Example
in the Dart
bindings:
// Java
public class _Example {
public void _printMessage() {
System.out.println("Hello from Java!");
}
}
// Dart Bindings - Boilerplate omitted for clarity.
class $_Example extends JObject {
void $_printMessage() { /* ... */ }
}
Inner classes
Java has the concept of inner classes, while Dart does not. Therefore, inner
classes are generated as separate classes named using the name of their
outer-class followed by a dollar sign ($
) followed by their original name.
For example:
// Java
public class Outer {
public class Inner {}
}
will be turned into:
// Dart Bindings - Boilerplate omitted for clarity.
class Outer extends JObject {}
class Outer$Inner extends JObject {}
Libraries
- jnigen Java Differences Lifecycle Threading Interface Implementation
- This library exports a high level programmatic API to jnigen, the entry point of which is runJniGenTask function, which takes run configuration as a JniGenTask.